'use strict'

const log = require('@djun-cli/log')
const Command = require('@djun-cli/command')
const Package = require('@djun-cli/package')
const { spinnerStart, execAsyncInstall } = require('@djun-cli/utils')
const userHome = require('user-home')
const inquirer = require('inquirer')
const fse = require('fs-extra')
const ejs = require('ejs')
const glob = require('glob')
const fs = require('fs')
const path = require('path')
const semver = require('semver')

const getProjectTemplate = require('./getProjectTemplate')

const TYPE_PROJECT = 'project'
const TYPE_COMPONENT = 'component'

const TEMPLATE_TYPE_NORMAL = 'normal'
const TEMPLATE_TYPE_CUSTOM = 'custom'

const WHITE_COMMAND = ['npm', 'cnpm']

class InitCommand extends Command {
  init() {
    this.projectName = this._argv[0] || null
    this.force = !!this._cmd.force
    log.verbose('this.projectName', this.projectName)
    log.verbose('this.force', this.force)
  }
  async exec() {
    try {
      // 准备阶段
      const projectInfo = await this.prepare()
      // 下载模板
      // 安装模板
      if (projectInfo) {
        log.verbose('projectInfo', projectInfo)
        this.projectInfo = projectInfo
        await this.downLoadTemplate()
        // 安装模板
        await this.installTempalte()
      }
    } catch (e) {
      log.error(e.message)
      if (process.env.LOG_LEVEL === 'verbose') {
        console.log(e)
      }
    }
  }

  async installTempalte() {
    if (this.tempalteInfo) {
      if (!this.tempalteInfo.type) {
        this.tempalteInfo.type = TEMPLATE_TYPE_NORMAL
      }
      if (this.tempalteInfo.type === TEMPLATE_TYPE_NORMAL) {
        // 标准安装
        await this.installNormalTemplate()
      } else if (this.tempalteInfo.type === TEMPLATE_TYPE_CUSTOM) {
        // 自定义安装
        await this.installCustomTemplate()
      } else {
        throw new Error('无法识别项目模板类型！')
      }
    } else {
      throw new Error('项目模板不存在！')
    }
  }

  checkCommand(cmd) {
    if (WHITE_COMMAND.includes(cmd)) {
      return cmd
    }
    return null
  }

  async execCommand(command, errMsg) {
    let ret
    if (command) {
      const cmdArray = command.split(' ')
      const cmd = this.checkCommand(cmdArray[0])
      if (!cmd) {
        throw new Error('命令不存在！命令：' + command)
      }
      const args = cmdArray.slice(1)
      ret = await execAsyncInstall(cmd, args, {
        stdio: 'inherit',
        cwd: process.cwd(),
      })
    }
    if (ret !== 0) {
      throw new Error(errMsg)
    }
    return ret
  }

  async ejsRender(options) {
    const dir = process.cwd()
    const projectInfo = this.projectInfo
    return new Promise((resolve, reject) => {
      glob(
        '**',
        {
          cwd: dir,
          ignore: options.ignore || '',
        },
        (err, files) => {
          if (err) {
            reject(err)
          }
          Promise.all(
            files.map((file) => {
              const filePath = path.resolve(dir, file)
              ejs.renderFile(filePath, projectInfo, (err, result) => {
                if (result) {
                  resolve(result)
                  fse.writeFileSync(filePath, result, {})
                }
                if (err) {
                  reject(err)
                }
              })
            })
          )
            .then(() => {
              resolve()
            })
            .catch((err) => {
              reject(err)
            })
        }
      )
    })
  }

  async installNormalTemplate() {
    // 拷贝模板至当前目录
    let spinner = spinnerStart('正在安装模板...')
    try {
      const tempaltePath = path.resolve(this.tempalteNpm.cacheFilePath, 'template')
      const targetPath = process.cwd()
      fse.ensureDirSync(tempaltePath)
      fse.ensureDirSync(targetPath)
      fse.copySync(tempaltePath, targetPath)
    } catch (e) {
      throw e
    } finally {
      spinner.stop(true)
      log.success('模板安装成功')
    }
    const ignore = ['node_modules/**', 'public/**']
    await this.ejsRender({ ignore })
    const { installCommand, startCommand } = this.tempalteInfo
    // 依赖安装
    await this.execCommand(installCommand, '依赖安装过程中失败')
    // 启动命令执行
    await this.execCommand(startCommand, '依赖安装过程中失败')
  }
  async installCustomTemplate() {
    console.log('安装自定义模板')
  }

  async downLoadTemplate() {
    const { projectTemplate } = this.projectInfo
    const tempalteInfo = this.tempalte.find((item) => item.npmName === projectTemplate)
    // console.log(tempalteInfo)
    const targetPath = path.resolve(userHome, '.djun-cli', 'tempalte')
    const storeDir = path.resolve(userHome, '.djun-cli', 'tempalte', 'node_modules')
    const { npmName, version } = tempalteInfo
    this.tempalteInfo = tempalteInfo
    const tempalteNpm = new Package({
      targetPath,
      storeDir,
      packageName: npmName,
      packageVersion: version,
    })

    if (!(await tempalteNpm.exists())) {
      const spinner = spinnerStart('正在下载模板。。。')
      try {
        await tempalteNpm.install()
      } catch (e) {
        throw e
      } finally {
        spinner.stop(true)
        if (await tempalteNpm.exists()) {
          log.success('下载模板成功')
          this.tempalteNpm = tempalteNpm
        }
      }
    } else {
      const spinner = spinnerStart('正在更新模板。。。')
      try {
        await tempalteNpm.update()
      } catch (e) {
        throw e
      } finally {
        spinner.stop(true)
        if (await tempalteNpm.exists()) {
          log.success('更新模板成功')
          this.tempalteNpm = tempalteNpm
        }
      }
    }
  }

  createTempalteChoice() {
    return this.tempalte.map((item) => ({
      value: item.npmName,
      name: item.name,
    }))
  }

  async getProjectInfo() {
    function isValidName(v) {
      return /^[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(v)
    }
    let projectInfo = {}
    let isProjectNameVaild = false
    if (isValidName(this.projectName)) {
      isProjectNameVaild = true
      projectInfo.projectName = this.projectName
    }
    // 选择创建项目或者组件
    const { type } = await inquirer.prompt({
      type: 'list',
      message: '请选择初始化类型',
      name: 'type',
      default: TYPE_PROJECT,
      choices: [
        {
          name: '项目',
          value: TYPE_PROJECT,
        },
        {
          name: '组件',
          value: TYPE_COMPONENT,
        },
      ],
    })
    log.verbose('type', type)
    if (type === TYPE_PROJECT) {
      const projectNamePrompt = {
        type: 'input',
        name: 'projectName',
        message: '请输入项目名称',
        default: '',
        validate: function (v) {
          const done = this.async()
          setTimeout(function () {
            if (!isValidName(v)) {
              done('请输入合法的项目名称')
              return
            }
            done(null, true)
          }, 0)
        },
        filter: function (v) {
          return v
        },
      }
      let projectPrompt = []
      if (!isProjectNameVaild) {
        projectPrompt.push(projectNamePrompt)
      }
      projectPrompt.push(
        {
          type: 'input',
          name: 'projectVersion',
          message: '请输入项目的版本号',
          default: '1.0.0',
          validate: function (v) {
            const done = this.async()
            setTimeout(function () {
              if (!semver.valid(v)) {
                done('请输入合法的版本号')
                return
              }
              done(null, true)
            }, 0)
          },
          filter: function (v) {
            if (!!semver.valid(v)) {
              return semver.valid(v)
            } else {
              return v
            }
          },
        },
        { type: 'list', name: 'projectTemplate', message: '请选择项目模板', choices: this.createTempalteChoice() }
      )
      const project = await inquirer.prompt(projectPrompt)
      projectInfo = {
        ...projectInfo,
        type,
        ...project,
      }
    } else if (type === TYPE_COMPONENT) {
    }

    if (projectInfo.projectName) {
      projectInfo.name = projectInfo.projectName
      projectInfo.className = require('kebab-case')(projectInfo.projectName).replace(/^-/, '')
    }

    if (projectInfo.projectVersion) {
      projectInfo.version = projectInfo.projectVersion
    }

    return projectInfo
    // 获取项目的基本信息
  }

  async prepare() {
    // 判断项目模板是否存在
    const tempalte = await getProjectTemplate()
    if (!tempalte || tempalte.length === 0) {
      throw new Error('项目模板不存在')
    }
    this.tempalte = tempalte
    const localPath = process.cwd()
    // 判断当前目录是否为空
    if (!this.isDirEmpty(localPath)) {
      let ifContinue = false
      if (!this.force) {
        // 询问是否继续创建
        ifContinue = (
          await inquirer.prompt({
            type: 'confirm',
            name: 'ifContinue',
            default: false,
            message: '当前文件夹不为空，是否继续创建项目？',
          })
        ).ifContinue
        if (!ifContinue) {
          return
        }
      }
      // 是否启动强制更新
      if (ifContinue || this.force) {
        const { confirmDelete } = await inquirer.prompt({
          type: 'confirm',
          name: 'confirmDelete',
          default: false,
          message: '是否确认清空当前目录下的文件？',
        })
        if (confirmDelete) {
          // 清空当前目录
          fse.emptyDirSync(localPath)
        }
      }
    }
    return this.getProjectInfo()
  }
  isDirEmpty(localPath) {
    // 文件过滤逻辑
    let fileList = fs.readdirSync(localPath)
    fileList = fileList.filter((file) => !file.startsWith('.') && ['node_modules'].indexOf(file) < 0)
    return !fileList || fileList.length <= 0
  }
}

function init(argv) {
  // console.log('init', projectName, cmdObj.force, process.env.CLI_TARGET_PATH)
  return new InitCommand(argv)
}

module.exports = init
module.exports.InitCommand = InitCommand
